//
//  FQDDatabase.m
//  FakeQDaily
//
//  Created by mewxiv on 8/18/16.
//  Copyright © 2016 Xensius. All rights reserved.
//

#import "FQDDatabase.h"
#import "FMDB.h"

static NSString *const FQDDatabaseFileName = @"FakeQDaily.sqlite";

@interface FQDDatabase ()

@property (nonatomic, strong) FMDatabaseQueue *databaseQueue;

@end

@implementation FQDDatabase

+ (instancetype)sharedDatabase
{
    static FQDDatabase *database;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        database = [[self class] new];
    });
    return database;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self openDatabase];
    }
    return self;
}

- (void)openDatabase
{
    NSString *dbFilePath = [[self applicationCachesDirecotry] stringByAppendingPathComponent:FQDDatabaseFileName];
    _databaseQueue = [FMDatabaseQueue databaseQueueWithPath:dbFilePath];
//    FQDLog(@"Database file path:%@", dbFilePath);
}

- (void)closeDatabase
{
    [self.databaseQueue close];
}

- (void)createTableIfNotExist:(NSString *)tableName columns:(NSDictionary<NSString *, NSString *> *)columns
{
    NSMutableString *columnsDesc = [NSMutableString string];
    for (NSString *columnName in columns) {
        NSString *columnAttribute = columns[columnName];
        [columnsDesc appendFormat:@"%@ %@,", columnName, columnAttribute];
    }
    [columnsDesc deleteCharactersInRange:NSMakeRange([columnsDesc length]-1, 1)];
    
    NSString *sql =
    [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@);", tableName, columnsDesc];
    

    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        BOOL isSuccess = [db executeUpdate:sql];
        if (!isSuccess) {
            FQDLog(@"unable to create table:%@ error:%@", tableName, [db lastErrorMessage]);
            abort();
        }
    }];
}

- (void)insertIntoTable:(NSString *)tableName columnValues:(NSDictionary<NSString *, id> *)columnValues
{
    NSMutableString *names = [NSMutableString string];
    NSMutableString *values = [NSMutableString string];
    for (NSString *columnName in columnValues) {
        [names appendFormat:@"%@,", columnName];
        [values appendFormat:@":%@,", columnName];
    }
    [names deleteCharactersInRange:NSMakeRange([names length]-1, 1)];
    [values deleteCharactersInRange:NSMakeRange([values length]-1, 1)];
    
    NSString *sql =
    [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES(%@);", tableName, names, values];
    
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        BOOL isSuccess = [db executeUpdate:sql withParameterDictionary:columnValues];
        if (!isSuccess) {
            FQDLog(@"unable to insert into table:%@ error:%@", tableName, [db lastErrorMessage]);
            abort();
        }
    }];
}


- (void)insertOrReplaceIntoTable:(NSString *)tableName columnValues:(NSDictionary<NSString *, id> *)columnValues
{
    NSMutableString *names = [NSMutableString string];
    NSMutableString *values = [NSMutableString string];
    for (NSString *columnName in columnValues) {
        [names appendFormat:@"%@,", columnName];
        [values appendFormat:@":%@,", columnName];
    }
    [names deleteCharactersInRange:NSMakeRange([names length]-1, 1)];
    [values deleteCharactersInRange:NSMakeRange([values length]-1, 1)];
    
    NSString *sql =
    [NSString stringWithFormat:@"INSERT OR REPLACE INTO %@(%@) VALUES(%@);", tableName, names, values];
    
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        BOOL isSuccess = [db executeUpdate:sql withParameterDictionary:columnValues];
        if (!isSuccess) {
            FQDLog(@"unable to insert or replace into table:%@ error:%@", tableName, [db lastErrorMessage]);
            abort();
        }
    }];
}

- (void)deleteFromTable:(NSString *)tableName whereCondition:(NSString *)condition
{
    NSString *sql =
    [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@;", tableName, condition];
    
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        BOOL isSuccess = [db executeUpdate:sql];
        if (!isSuccess) {
            FQDLog(@"unable to delete from table:%@ error:%@", tableName, [db lastErrorMessage]);
            abort();
        }
    }];
}

- (void)deleteAllFromTable:(NSString *)tableName
{
    NSString *sql =
    [NSString stringWithFormat:@"DELETE FROM %@;", tableName];
    
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        BOOL isSuccess = [db executeUpdate:sql];
        if (!isSuccess) {
            FQDLog(@"unable to delete from table:%@ error:%@", tableName, [db lastErrorMessage]);
            abort();
        }
    }];
}

- (BOOL)updateTable:(NSString *)tableName setColumnValues:(NSDictionary<NSString *, id> *)columnValues whereCondition:(NSString *)condition
{
    NSMutableString *updateValues = [NSMutableString string];
    for (NSString *columnName in columnValues) {
        id columnValue = columnValues[columnName];
        [updateValues appendFormat:@"%@ = '%@',", columnName, columnValue];
    }
    [updateValues deleteCharactersInRange:NSMakeRange([updateValues length]-1, 1)];
    
    NSString *sql =
    [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@", tableName, updateValues, condition];
    
    __block BOOL hasChanges = NO;
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        BOOL isSuccess = [db executeUpdate:sql];
        if (!isSuccess) {
            FQDLog(@"unable to update from table:%@ error:%@", tableName, [db lastErrorMessage]);
            abort();
        }
        hasChanges = db.changes;
    }];
    return hasChanges;
}

- (id)selectColumn:(NSString *)columnName fromTable:(NSString *)tableName whereCondition:(NSString *)condition
{
    NSString *sql =
    [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@;", columnName, tableName, condition];
    
    __block id result = nil;
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        FMResultSet *resultSet = [db executeQuery:sql];
        
        if ([resultSet next]) {
            result = [resultSet objectForColumnName:columnName];
        }
        
        [resultSet close];
    }];
    
    return result;
}

- (NSArray *)selectColumns:(NSArray<NSString *> *)columnNames fromTable:(NSString *)tableName whereCondition:(NSString *)condition
{
    NSMutableString *columnsString = [NSMutableString string];
    for (NSString *columnName in columnNames) {
        [columnsString appendFormat:@"%@,", columnName];
    }
    [columnsString deleteCharactersInRange:NSMakeRange([columnsString length]-1, 1)];
    
    NSString *sql =
    [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@;", columnsString, tableName, condition];
    
    NSMutableArray *results = [NSMutableArray array];
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        FMResultSet *resultSet = [db executeQuery:sql];
        
        while ([resultSet next]) {
            [results addObject:[resultSet resultDictionary]];
        }
        
        [resultSet close];
    }];
    
    return [results copy];
}

- (NSArray *)selectAllColumnsFromTable:(NSString *)tableName whereCondition:(NSString *)condition
{
    NSString *sql =
    [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@;", tableName, condition];
    
    NSMutableArray *results = [NSMutableArray array];
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        FMResultSet *resultSet = [db executeQuery:sql];
        
        while ([resultSet next]) {
            [results addObject:[resultSet resultDictionary]];
        }
        
        [resultSet close];
    }];
    
    return [results copy];
}

- (void)executeSQL:(NSString *)sql
{
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        BOOL isSuccess = [db executeUpdate:sql];
        if (!isSuccess) {
            FQDLog(@"unable to execute sql:%@ error:%@", sql, [db lastErrorMessage]);
            abort();
        }
    }];
}

- (BOOL)tableExists:(NSString *)tableName
{
    __block BOOL isExists = NO;
    [self.databaseQueue inDatabase:^(FMDatabase *db) {
        isExists = [db tableExists:tableName];
    }];
    return isExists;
}

- (NSString *)applicationCachesDirecotry
{
    NSArray *urls = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory
                                                        inDomains:NSUserDomainMask];
    NSURL *url = [urls firstObject];
    NSString *documentDirectoryPath = [url path];
    return documentDirectoryPath;
}

@end

